#include "ProjectileEnemy.h"
#include "Map.h"

ProjectileEnemy::ProjectileEnemy()
	: Enemy()
	, kMaxProjectiles (100)
	, mProjectileIndex (0)
	, mProjectileDelay (1.0f)
	, mCurrentHealth(5)
{
}

ProjectileEnemy::~ProjectileEnemy()
{
}

void ProjectileEnemy::Load()
{
	//load sprite
	mSprite.Add("tacomascot1.png");
	mSprite.Add("tacomascot2.png");
	
	//load projectiles
	for(int i=0; i<kMaxProjectiles; ++i)
		mProjectiles[i].Load("taco");

	//load health
	mCurrentHealth.Load();

	mLarryDamage.Load("larrydamage.wav");
	mDeathSound.Load("tacodeath.wav");
}

void ProjectileEnemy::Unload()
{
	//unload sprite
	mSprite.Unload();

	//unload projectiles
	for(int i=0; i<kMaxProjectiles; ++i)
		mProjectiles[i].Unload();

	//unload health
	mCurrentHealth.Unload();

	mLarryDamage.Unload();
	mDeathSound.Unload();
}

void ProjectileEnemy::Update(float deltaTime, Map& map, Character& character)
{
	if(mActive)
	{
		mSprite.Update(deltaTime);
		VelocityShift(map);

		FireProjectile(deltaTime);
		for(int i=0; i<kMaxProjectiles; ++i)
			mProjectiles[i].Update(deltaTime, map);
		DealProjectileDamage(character);

		mPosition += mVelocity * deltaTime;

		//update health and check if still alive
		mCurrentHealth.Update(deltaTime, mPosition);
		if(!mCurrentHealth.IsAlive())
			Kill();
	}
}

void ProjectileEnemy::Render(const SVector2& viewOffset)
{
	//only render active ProjectileEnemys
	if(mActive)
	{
		for(int i=0; i<kMaxProjectiles; ++i)
			mProjectiles[i].Render(viewOffset);

		int width = mSprite.GetWidth();
		int height = mSprite.GetHeight();

		SVector2 offset(width * 0.5f, height * 0.5f);
		SVector2 renderPosition = mPosition - offset - viewOffset;

		mSprite.SetPosition(renderPosition);

		if(mVelocity.x <= 0.0f)
			mSprite.SetFlipH(true);
		else
			mSprite.SetFlipH(false);

		mSprite.Render();

		//Graphics_DebugRect(GetBoundingBox());
		mCurrentHealth.Render(viewOffset);
	}
}

void ProjectileEnemy::Spawn(const SVector2& pos, const SVector2& vel, const SVector2& projVel)
{
	mPosition = pos;
	mVelocity = vel;
	mProjectileVelocity = projVel;
	mActive = true;
	mSprite.Play(2.0f, true);
}

void ProjectileEnemy::Kill()
{
	//set false to stop update and render functions
	mActive = false;
	mSprite.Stop();
	mSprite.Reset();
	mDeathSound.Play(false);
}

SRect ProjectileEnemy::GetBoundingBox() const
{
	//need to create an approximate shape for collision etc.
	SRect boundingBox;
	
	//defining x and y minimums of bounding box
	//using magic numbers containing size of content on sprite
	boundingBox.min.x = mPosition.x - 32.0f;
	boundingBox.max.x = mPosition.x + 32.0f;
	boundingBox.min.y = mPosition.y - 60.0f;
	boundingBox.max.y = mPosition.y + 60.0f;

	//moving in positive x, check right line segment of box etc.

	return boundingBox;
}

void ProjectileEnemy::VelocityShift(const Map& map)
{
	SRect boundingBox = GetBoundingBox();

	//TESTING VERTICAL COLLISION
	if(mVelocity.y >= 0)
	{
		SLineSegment segment = boundingBox.GetBottomSegment();
		SRect collisionBox;

		if(map.TestCollision(segment, collisionBox)) //if collision has occured
			mVelocity.y *= -1; //reverse y velocity
	}
	else if(mVelocity.y < 0)
	{
		SLineSegment segment = boundingBox.GetTopSegment();
		SRect collisionBox;

		if(map.TestCollision(segment, collisionBox))
			mVelocity.y *= -1;
	}

	//TESTING HORIZONTAL COLLISION
	if(mVelocity.x >= 0)
	{
		SLineSegment segment = boundingBox.GetRightSegment();
		SRect collisionBox;

		if(map.TestCollision(segment, collisionBox))
			mVelocity.x *= -1;
	}
	else if(mVelocity.x < 0)
	{
		SLineSegment segment = boundingBox.GetLeftSegment();
		SRect collisionBox;

		if(map.TestCollision(segment, collisionBox))
			mVelocity.x *= -1;
	}

}

void ProjectileEnemy::FireProjectile(float deltaTime)
{
	mProjectileDelay -= deltaTime;

	if(mProjectileDelay <= 0)
	{
		if(!mProjectiles[mProjectileIndex].isActive())
		{
			SVector2 pos = mPosition;
			mProjectiles[mProjectileIndex].Fire(pos, mProjectileVelocity);
			mProjectileIndex = (mProjectileIndex + 1) % kMaxProjectiles;
		}
		mProjectileDelay = 1.0f;
	}
}

void ProjectileEnemy::DealProjectileDamage(Character& character)
{
	for(int p=0; p<kMaxProjectiles; ++p)
	{
		if(mProjectiles[p].isActive())
		{
			//check if(player character active)
			SCircle pCircle = mProjectiles[p].GetBoundingCircle();
			SCircle cCircle = character.GetBoundingCircle();

			float xDiff = cCircle.center.x - pCircle.center.x;
			float yDiff = cCircle.center.y - pCircle.center.y;

			float distance = sqrt(xDiff * xDiff + yDiff * yDiff);
			float radii = cCircle.radius + pCircle.radius;

			if(distance <= radii)
			{
				if(!character.IsShielded())
				{
					character.mCurrentHealth.TakeDamage(1);
					mProjectiles[p].Kill();
					if(character.mCurrentHealth.GetCurrentHealth() >= 1)
						mLarryDamage.Play(false);
					break;
				}
				else
				{
					mProjectiles[p].ReverseVelocity();
					break;
				}
			}
		}
	}
}